#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using std::cout;
using std::endl;
int min(int a,int b){
    (a>b)?(b):(a);
}



#define MAXNITEMS 1000000
#define MAXNTHREADS 100
int nitems;
struct{
    pthread_mutex_t mutex;
    int buff[MAXNITEMS];
    int nput;
    int nval;
}shared = {
    PTHREAD_MUTEX_INITIALIZER
};

void* produce(void*);
void* consume(void*);

int main(int argc, char** argv)
{
    int i, nthreads, count[MAXNTHREADS];
    pthread_t tid_produce[MAXNTHREADS], tid_consume;
    
    if(argc != 3){
        cout << "usage: prodcons2 <#items> <#threads>" << endl;
    }
    
    nitems = min(atoi(argv[1]), MAXNITEMS);
    nthreads = min(atoi(argv[2]), MAXNTHREADS);
    //set_concurrency(nthreads);
    
    for(int i = 0; i < nthreads; ++i){
        count[i] = 0;
        pthread_create(&tid_produce[i], NULL, produce, &count[i]);
    }
    //wait for all the producer threads
    for( int i = 0; i < nthreads; ++i){
        pthread_join(tid_produce[i], NULL);
        cout << "count[" << i << "]=" << count[i] << endl;
    }
    
    pthread_create(&tid_consume, NULL, consume, NULL);
    pthread_join(tid_consume, NULL);
    exit(0);
}
void* produce(void* arg)
{
    for(;;){
        pthread_mutex_lock(&shared.mutex);
        if(shared.nput >= nitems){
            pthread_mutex_unlock(&shared.mutex);
            return NULL;
        }
        shared.buff[shared.nput] = shared.nval;
        shared.nput ++;
        shared.nval ++;
        pthread_mutex_unlock(&shared.mutex);
        *((int*)arg) += 1;
    }
}
void* consume(void* arg)
{
    int i;
    for(int i = 0; i < nitems; ++i){
        if(shared.buff[i] != i){
            cout << "buff[" << i << "] = " << shared.buff[i] << endl;
        }
    }
    return NULL;
}

    
